package com.example.demo.scheduledtask;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.example.demo.common.Constant;
import com.example.demo.config.ErpConfig;
import com.example.demo.mapper.AsyncWorkorderMapper;
import com.example.demo.mapper.PoMpsinfoMapper;
import com.example.demo.mapper.WmsPurchaseMapper;
import com.example.demo.utils.SoapXmlUtil;
import com.example.demo.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * @author : Zhang.yt
 * @date : 2024/7/29
 */
@Component
@Slf4j
@DS("wms")
public class PickingOutCallback {
    @Resource
    private WmsPurchaseMapper wmsPurchaseMapper;

    @Autowired
    private SoapXmlUtil soapXmlUtil;

    @Autowired
    PoMpsinfoMapper poMpsinfoMapper;

    @Resource
    private ErpConfig erpConfig;

    @Resource
    private AsyncWorkorderMapper asyncWorkorderMapper;


    /**
     * 生产工单（领料单）
     */
    @Scheduled(fixedDelay = 8 * 1000)//开启定时同步
    //@Async(value = "taskExecutor")
    public void pickingOutCallback() {
        //查询没有回调的数据
        PickingOutVo pickingOutVo = wmsPurchaseMapper.getPickingOutCallback();

//        List<String> outnoList = pickingOutCallback.stream().map(PickingOutVo::getSfda014).collect(Collectors.toList());
        if (ObjectUtil.isEmpty(pickingOutVo)) {
            log.info("未查询到生产工单（领料单）数据，修改过账失败数据重新进行回写");
            wmsPurchaseMapper.pickingOutCallbackLose();
            return;
        }

        try {
            //超过60秒未获取到锁就退出
//            if (!lock.tryLock(60, TimeUnit.SECONDS)) {
//                return;
//            }
            //直接修改状态为带返回避免下次查询到数据
            log.info("查询出的生产领料单->{}", JSONObject.toJSONString(pickingOutVo));
            //捕获异常，设置单据状态为失败，避免总是取到该单据导致后续任务无法处理
            //根据没有回调的数据查询细表
            List<PickingOutVoReceiptListVo> pickingOutVoReceiptList = wmsPurchaseMapper.getPickingOutReceiptListCallback(pickingOutVo.getSfda014(), pickingOutVo.getSbillno(),pickingOutVo.getSfda004());
            if (CollUtil.isEmpty(pickingOutVoReceiptList)) {
                log.info("查询出的生产领料单明细信息为空->{}", JSONObject.toJSONString(pickingOutVo));
                wmsPurchaseMapper.updateReGetMaterialCallback(pickingOutVo.getSfda014(), "查询出的生产领料单明细信息为空", 2);
                return;
            }
            List<String> stringList = pickingOutVoReceiptList.stream().map(PickingOutVoReceiptListVo::getSfdc001).collect(Collectors.toList());
            if (!stringList.contains(pickingOutVo.getSbillno())) {
                log.info("明细出库工单与住表出库工单不一致");
                log.info("查询出的生产领料单信息->{}", JSONObject.toJSONString(pickingOutVo));
                log.info("查询出的生产领料单明细信息->{}", JSONObject.toJSONString(pickingOutVoReceiptList));
                return;
            }
            //优先占用防止计算逻辑再次查询到该工单
            wmsPurchaseMapper.updateReGetMaterialCallback(pickingOutVo.getSfda014(), "erp待返回", 3);

//            Map<String, List<PickingOutVoReceiptListVo>> listMap = pickingOutVoReceiptList.stream().collect(Collectors.groupingBy(PickingOutVoReceiptListVo::getOutno));

//            for (PickingOutVo pickingOutVo : pickingOutCallback) {
            //工单发出回调
            this.workOrderIssue(pickingOutVo.getSfda014());
            pickingOutVo.setActionType(Constant.ActionType_I);
            pickingOutVo.setSfdadocno(Constant.PMDSDOCNO_5409);
            pickingOutVo.setSfdasite(Constant.PMDSSITE_AMA);
//                List<PickingOutVoReceiptListVo> pickingOutVoReceiptListVoList = listMap.get(pickingOutVo.getSfda014());
            List<PickingOutVoReceiptListReq> pickingOutVoReceiptListReqs = BeanUtil.copyToList(pickingOutVoReceiptList, PickingOutVoReceiptListReq.class);
            //分发项次项序  返回要修改的数据
            if (ObjectUtil.isEmpty(pickingOutVoReceiptListReqs)) {
                log.info("非常见的数据处理问题，请联系开发人员处理", pickingOutVo.getSfda014());
                wmsPurchaseMapper.updateReGetMaterialCallback(pickingOutVo.getSfda014(), "非常见的数据处理问题，请联系开发人员处理", 2);
                return;
            }
            List<AsyncWorkorderVo> asyncWorkorderVos = distributeItemOrder(pickingOutVoReceiptListReqs, pickingOutVo.getSfda014());
            log.info(pickingOutVoReceiptListReqs.toString());
            if (CollUtil.isEmpty(asyncWorkorderVos)) {
                log.info("未获取到出库单工单信息跳出本次循环:出库单号:{}", pickingOutVo.getSfda014());
                return;
            } else {
                //查询库存管理特征
                for (PickingOutVoReceiptListReq pickingOutVoReceiptListReq : pickingOutVoReceiptListReqs) {
                    String inag003 = wmsPurchaseMapper.getInventoryInag003(pickingOutVoReceiptListReq);
                    if (ObjectUtil.isNotEmpty(inag003)) {
                        pickingOutVoReceiptListReq.setSfdc016(inag003);
                    }
                }
            }
            String resMessage = soapXmlUtil.getSoapXml("ReGetMaterial", "sfda_t", "sfdc_t", pickingOutVo, pickingOutVoReceiptListReqs);
            //转换为soap消息
            log.info("生产领料回写数据:{}", resMessage);
            //状态处理为erp待返回
            wmsPurchaseMapper.updateReGetMaterialCallback(pickingOutVo.getSfda014(), "erp待返回", 3);
            //发送soap消息，并解析结果
            String result;
            try {
                result = soapXmlUtil.sendSoapMessageNew(resMessage, erpConfig.getUrl());
            } catch (Exception e) {
                result = soapXmlUtil.sendSoapMessageNew(resMessage, erpConfig.URL2);
            }

            //调用等待
            if (pickingOutVoReceiptListReqs.size() >= 50) {
                Thread.sleep(60 * 1000);
            } else if (pickingOutVoReceiptListReqs.size() >= 30) {
                Thread.sleep(20 * 1000);
            } else if (pickingOutVoReceiptListReqs.size() >= 10) {
                Thread.sleep(5 * 1000);
            }
            log.info("soap接口生产领料回调->{}", result);
            XmlResp xmlResp = soapXmlUtil.analysisXml(result);
            if (xmlResp.getCode().equals("0")) {
                //更新相应表状态为已下发
                wmsPurchaseMapper.updateReGetMaterialCallback(pickingOutVo.getSfda014(), xmlResp.getData().get("sfdadocno"), 1);
                //更新工单表数据
                asyncWorkorderMapper.updateBatch(asyncWorkorderVos);
                //新增记录数据
                newRecordData(pickingOutVo.getSfda014(), pickingOutVoReceiptListReqs);
            } else {
                //更新相应表状态为已下发
                wmsPurchaseMapper.updateReGetMaterialCallback(pickingOutVo.getSfda014(), xmlResp.getMessage(), 2);
            }
        } catch (Exception e) {
            wmsPurchaseMapper.updateReGetMaterialCallback(pickingOutVo.getSfda014(), "非常见的数据处理问题，请联系开发人员处理", 2);
            e.printStackTrace();
        }

//        finally {
//            log.error("finally释放锁{}", this.getClass().getName());
//            if (ObjectUtil.isNotEmpty(lock) && lock.isHeldByCurrentThread()) {
//                lock.unlock();
//            }
//        }
    }


    public void workOrderIssue(String orderNo) {
        WorkOrderIssueVo workOrderIssueVo = wmsPurchaseMapper.getWorkOrderIssue(orderNo);
        if (ObjectUtils.isEmpty(workOrderIssueVo)) {
            return;
        }

        WorkOrderIssueReq workOrderIssueReq = BeanUtil.toBean(workOrderIssueVo, WorkOrderIssueReq.class);
        workOrderIssueReq.setUser(workOrderIssueVo.getUserNO());
        String resMessage = soapXmlUtil.getSoapXml("WorkOrderIssue", "sfaa_t", workOrderIssueReq);
        try {
            //转换为soap消息
            log.info("soap工单发出接口回调->{}", resMessage);
            //发送soap消息，并解析结果
            String result;
            try {
                result = soapXmlUtil.sendSoapMessageNew(resMessage, erpConfig.getUrl());
            } catch (Exception e) {
                result = soapXmlUtil.sendSoapMessageNew(resMessage, erpConfig.URL2);
            }
            log.info("soap工单发出接口回调返回->{}", result);
            XmlResp xmlResp = soapXmlUtil.analysisXml(result);
            if (xmlResp.getCode().equals("0")) {
                wmsPurchaseMapper.insertWorkOrderIssue(workOrderIssueVo, xmlResp.getCode(), xmlResp.getData().get("sfaadocno"));
            } else {
                //更新相应表状态为已下发
                wmsPurchaseMapper.insertWorkOrderIssue(workOrderIssueVo, xmlResp.getCode(), xmlResp.getMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void newRecordData(String orderno, List<PickingOutVoReceiptListReq> pickingOutVoReceiptListReqs) {
        List<BackRecordVo> backRecordVoList = new ArrayList<>();
        for (PickingOutVoReceiptListReq pickingOutVoReceiptListReq : pickingOutVoReceiptListReqs) {
            BackRecordVo backRecordVo = new BackRecordVo();
            backRecordVo.setWorkno(pickingOutVoReceiptListReq.getSfdc001());
            backRecordVo.setItem(pickingOutVoReceiptListReq.getSfdc002());
            backRecordVo.setTerm(pickingOutVoReceiptListReq.getSfdc003());
            backRecordVo.setMcode(pickingOutVoReceiptListReq.getSfdc004());
            backRecordVo.setNum(pickingOutVoReceiptListReq.getSfdc007());
            backRecordVo.setOrderno(orderno);
            backRecordVo.setBatchno(pickingOutVoReceiptListReq.getSfdc014());
            backRecordVoList.add(backRecordVo);
        }
        if (CollUtil.isNotEmpty(backRecordVoList)) {
            asyncWorkorderMapper.saveBatchBackRecord(backRecordVoList);
        }
    }


    private List<AsyncWorkorderVo> distributeItemOrder(List<PickingOutVoReceiptListReq> pickingOutVoReceiptListReqs, String outno) {
        //查询
        //获取工单号
        String workOrderNo = pickingOutVoReceiptListReqs.get(0).getSfdc001();
        List<String> mcodeList = pickingOutVoReceiptListReqs.stream().map(PickingOutVoReceiptListReq::getSfdc004).distinct().collect(Collectors.toList());

        //每次都重新获取下工单信息，发料和已发，避免工单变更造成未及时获取到最新领料需求
        //1、基于工单先删除原有的数据 以下存储过程中有删除数据这里不需要删除
//        asyncWorkorderMapper.deleteByWordOrderNo(workOrderNo);
        //2、拉取工单信息到async_workorder
        asyncWorkorderMapper.updateAsyncWorkorder(workOrderNo);

        //查询工单是否存在
        String asyncWorkorder = asyncWorkorderMapper.getAsyncWorkorder(workOrderNo);
        if (ObjectUtil.isEmpty(asyncWorkorder)) {
            log.error("单号工单信息未查到:{}", workOrderNo);
            wmsPurchaseMapper.updateReGetMaterialCallback(outno, "未获取到出库单工单信息，工单可能已结案或已删除", 2);
            return null;
        }
        Map<String, List<PickingOutVoReceiptListReq>> mcodeListMap = pickingOutVoReceiptListReqs.stream().collect(Collectors.groupingBy(PickingOutVoReceiptListReq::getSfdc004));
        for (Map.Entry<String, List<PickingOutVoReceiptListReq>> entry : mcodeListMap.entrySet()) {
            String mcode = entry.getKey();

            List<PickingOutVoReceiptListReq> entryValue = entry.getValue();
            BigDecimal mcodeNum = entryValue.stream().map(PickingOutVoReceiptListReq::getSfdc007).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (mcodeNum.compareTo(BigDecimal.ZERO) <= 0) {
                //更新相应表状态为已下发
                wmsPurchaseMapper.updateReGetMaterialCallback(outno, "料号" + mcode + "发料数量为0！本出库单未回写，请确认！", 2);
                return null;
            }
            BigDecimal asyncWorkorderMnum = asyncWorkorderMapper.getAsyncWorkorderMnum(workOrderNo, mcode);
            if (ObjectUtil.isEmpty(asyncWorkorderMnum)) {
                wmsPurchaseMapper.updateReGetMaterialCallback(outno, "料号" + mcode + "在该工单中未查到！本出库单未回写，请确认！", 2);
                return null;
            }
            //本次发料总数量小于剩余发料总数量不会写直接报错
            log.info("料号:{},本次发料数量:{},单据剩余发料数量:{}", mcode, mcodeNum, asyncWorkorderMnum);
            if (mcodeNum.compareTo(asyncWorkorderMnum) > 0) {
                //更新相应表状态为已下发
                wmsPurchaseMapper.updateReGetMaterialCallback(outno, "料号" + mcode + ",本次发料数量:" + mcodeNum + ",单据剩余发料数量:" + asyncWorkorderMnum, 2);
                return null;
            }
        }
        //获取工单信息
        List<AsyncWorkorderVo> distributeItemOrder = asyncWorkorderMapper.getDistributeItemOrder(workOrderNo, mcodeList);
        if (CollUtil.isEmpty(distributeItemOrder)) {
            //更新相应表状态为已下发
            wmsPurchaseMapper.updateReGetMaterialCallback(outno, workOrderNo + "工单发料数据已足够！本出库单未回写，请确认！", 2);
            return null;
        }
        List<PickingOutVoReceiptListReq> newPickingOutVoReceiptListReqs = new ArrayList<>();
        //分发工单信息
        for (PickingOutVoReceiptListReq pickingOutVoReceiptListReq : pickingOutVoReceiptListReqs) {
            //料号
            String sfdc004 = pickingOutVoReceiptListReq.getSfdc004();
            //数量
            BigDecimal sfdc007 = pickingOutVoReceiptListReq.getSfdc007();
            for (AsyncWorkorderVo asyncWorkorderVo : distributeItemOrder) {
                if (sfdc007.compareTo(BigDecimal.ZERO) == 0) {
                    break;
                }
                //料号相同时
                if (asyncWorkorderVo.getMcode().equals(sfdc004) && asyncWorkorderVo.getTotal().compareTo(asyncWorkorderVo.getNum()) > 0) {
                    //项次数量足够
                    if (asyncWorkorderVo.getTotal().compareTo(sfdc007.add(asyncWorkorderVo.getNum())) >= 0 && ObjectUtil.isEmpty(pickingOutVoReceiptListReq.getSfdc002())) {
                        asyncWorkorderVo.setNum(sfdc007.add(asyncWorkorderVo.getNum()));
                        //项次
                        pickingOutVoReceiptListReq.setSfdc002(asyncWorkorderVo.getItem());
                        //项序
                        pickingOutVoReceiptListReq.setSfdc003(asyncWorkorderVo.getTerm());
                        sfdc007 = BigDecimal.ZERO;
                        //领完数量不够时寻找下一个项次
                    } else {
                        //已经有项次时 获取下一个项次
                        if (ObjectUtil.isNotEmpty(pickingOutVoReceiptListReq.getSfdc002())) {
                            //剩余数量大于0 创建出一个新的出库单
                            if (sfdc007.compareTo(BigDecimal.ZERO) > 0) {
                                PickingOutVoReceiptListReq newReq = BeanUtil.copyProperties(pickingOutVoReceiptListReq, PickingOutVoReceiptListReq.class);
                                newReq.setSfdc007(sfdc007);
                                //项次
                                newReq.setSfdc002(asyncWorkorderVo.getItem());
                                //项序
                                newReq.setSfdc003(asyncWorkorderVo.getTerm());
                                if (asyncWorkorderVo.getTotal().compareTo(sfdc007.add(asyncWorkorderVo.getNum())) >= 0) {
                                    newReq.setSfdc007(sfdc007);
                                    asyncWorkorderVo.setNum(sfdc007.add(asyncWorkorderVo.getNum()));
                                    sfdc007 = BigDecimal.ZERO;
                                } else {
                                    //项次剩余要领取数量
                                    BigDecimal subtract = asyncWorkorderVo.getTotal().subtract(asyncWorkorderVo.getNum());
                                    newReq.setSfdc007(subtract);
                                    asyncWorkorderVo.setNum(asyncWorkorderVo.getTotal());
                                    //出库剩余数量
                                    sfdc007 = sfdc007.subtract(subtract);
                                }
                                newPickingOutVoReceiptListReqs.add(newReq);
                            }
                        } else {
                            //剩余要领取数量
                            BigDecimal subtract = asyncWorkorderVo.getTotal().subtract(asyncWorkorderVo.getNum());
                            asyncWorkorderVo.setNum(asyncWorkorderVo.getTotal());
                            //项次
                            pickingOutVoReceiptListReq.setSfdc002(asyncWorkorderVo.getItem());
                            //项序
                            pickingOutVoReceiptListReq.setSfdc003(asyncWorkorderVo.getTerm());
                            pickingOutVoReceiptListReq.setSfdc007(subtract);
                            //出库剩余数量
                            sfdc007 = sfdc007.subtract(subtract);
                        }
                    }
                }
            }
        }

        if (CollUtil.isNotEmpty(newPickingOutVoReceiptListReqs)) {
            pickingOutVoReceiptListReqs.addAll(newPickingOutVoReceiptListReqs);
        }

        //清除小于0的数据
        return distributeItemOrder.stream().filter(item -> item.getNum().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());
    }

}
